﻿using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Numbers;
using Numbers.Arithmatic;
using Microsoft.Silverlight.Testing;

namespace t_Numbers
{
    [TestClass]
    public class t_Multiplication
    {
        [TestMethod]
        public void TestCreation()
        {
            Value r = new Value();
            Value m1 = new Value();

            Multiplication.Create(new Operand(r), new Operand[] { new Operand(m1) });
            Assert.AreEqual(0.0, r.Val, "Initial value should be zero");
            Assert.AreEqual(0.0, m1.Val, "Iniital value should be zero of the other side!");

            Value r2 = new Value();
            Value m2 = new Value() { Val = 10.0 };
            Multiplication.Create(new Operand(r2), new Operand[] { new Operand(m2) });
            Assert.AreEqual(10.0, r2.Val, "Expected that the value is 10 - this is an equal operation!");

            Value r3 = new Value();
            Value m3 = new Value() { Val = 2.0 };
            Value m4 = new Value() { Val = 3.0 };
            Multiplication.Create(new Operand(r3), new Operand[] { new Operand(m3), new Operand(m4) });
            Assert.AreEqual(6.0, r3.Val, "Expected the result to have been multiplied!");
        }

        [TestMethod]
        public void TestTSSetCorrectly()
        {
            Value r = new Value();
            Value m1 = new Value();
            Value m2 = new Value();
            Multiplication.Create(new Operand(r), new Operand[] { new Operand(m1), new Operand(m2) });

            Assert.AreEqual(r.TransactionManager, m1.TransactionManager, "r and m1 TS should be the same");
            Assert.AreEqual(r.TransactionManager, m2.TransactionManager, "r and m2 TS should be the same");
            Assert.IsNotNull(r.TransactionManager, "r TS should not be null");
        }

        [TestMethod]
        public void TestEqual()
        {
            Value r = new Value();
            Value m1 = new Value();
            Multiplication.Create(new Operand(r), new Operand[] { new Operand(m1) });

            m1.Val = 5.0;
            Assert.AreEqual(5.0, r.Val, "Expected the two guys to become equal with each other!");

            r.Val = 10.0;
            Assert.AreEqual(10.0, m1.Val, "Expected the two guys to become euqal when we set the result!");
        }

        [TestMethod]
        public void TestTwoOperands()
        {
            Value r = new Value();
            Value m1 = new Value();
            Value m2 = new Value();
            Multiplication.Create(new Operand(r), new Operand[] { new Operand(m1), new Operand(m2) });

            m1.Val = 10.0;
            Assert.AreEqual(0.0, r.Val, "Expected the result to still be zero!");

            m2.Val = 4.0;
            Assert.AreEqual(40.0, r.Val, "Expected good multiplication to have occured!");

            r.Val *= 4; ;
            Assert.AreEqual(20, m1.Val, "Expected doubling of m1 when we multiplied by 4.");
            Assert.AreEqual(8.0, m2.Val, "Expected boulding of m2 when we multiplied by 4.");
        }

        [TestMethod]
        public void TestZeroOperands()
        {
            Value r = new Value();
            Value m1 = new Value();
            Value m2 = new Value();
            Multiplication.Create(new Operand(r), new Operand[] { new Operand(m1), new Operand(m2) });

            r.Val = 16;
            Assert.AreEqual(4.0, m1.Val, "Expecting sqrt to go to m1");
            Assert.AreEqual(4.0, m2.Val, "Expecting sqrt to go to m2");

            m1.Val = 0;
            r.Val = 20;
            Assert.AreEqual(5.0, m1.Val, "Expecting back propagation to up the zero elements only");
        }

        [TestMethod]
        public void TestAllFixedOperands()
        {
            Value r = new Value();
            Value m1 = new Value();
            Value m2 = new Value();
            Multiplication.Create(new Operand(r), new Operand[] { new Operand(m1, true), new Operand(m2, true) });

            m1.Val = 2.0;
            m2.Val = 3.0;
            Assert.AreEqual(6.0, r.Val, "Expecing correct multiplication");
            r.Val = 10.0;
            Assert.AreEqual(6.0, r.Val, "Expecting the fixed operands to prevent anything from happening at all!");

            m1.Val = 0.0;
            Assert.AreEqual(0.0, r.Val, "expected zero when resetting to zero");
            r.Val = 10.0;
            Assert.AreEqual(0.0, r.Val, "Even with a zero we should not have been able to swtich to something new!");
        }

        [TestMethod]
        public void TestOneFixedOperands()
        {
            Value r = new Value();
            Value m1 = new Value();
            Value m2 = new Value();
            Multiplication.Create(new Operand(r), new Operand[] { new Operand(m1), new Operand(m2, true) });

            m1.Val = 2.0;
            m2.Val = 2.0;
            Assert.AreEqual(4.0, r.Val, "Expecing correct multiplication");
            r.Val = 10.0;
            Assert.AreEqual(10.0, r.Val, "Should have allowed the change!");
            Assert.AreEqual(2.0, m2.Val, "Should have remained the same!");
            Assert.AreEqual(5.0, m1.Val, "m1 should have come up to 5 to compensate!");
        }

        [TestMethod]
        public void TestMiddleFixed()
        {
            Value r = new Value();
            Value m1 = new Value();
            Value m2 = new Value();
            Multiplication.Create(new Operand(r, true), new Operand[] { new Operand(m1), new Operand(m2, true) });

            r.Val = 4.0;
            Assert.AreEqual(0.0, r.Val, "Expecting the result to be zero");
            Assert.AreEqual(0.0, m1.Val, "Expecting the middle guy to be zero");
            Assert.AreEqual(0.0, m2.Val, "Expecting the last guy to be zero too!");

            m2.Val = 5.0;
            Assert.AreEqual(5.0, m2.Val, "Expecting m2 to be allowed to change");
            Assert.AreEqual(0.0, m1.Val, "Expecting the middle guy to be 0");
            Assert.AreEqual(0.0, r.Val, "Expecting the last guy to be 0 too!");
        }

        [TestMethod]
        public void TestFixedResultOperands()
        {
            Value r = new Value();
            Value m1 = new Value();
            Value m2 = new Value();
            Multiplication.Create(new Operand(r, true), new Operand[] { new Operand(m1), new Operand(m2) });

            m1.Val = 2.0;
            Assert.AreEqual(2.0, m1.Val, "m1 should have been allowed to change because it is being multiplied by zero!");
            Assert.AreEqual(0.0, m2.Val, "m2 should still be zero so that mult is zero!");
            m2.Val = 2.0;
            Assert.AreEqual(2.0, m2.Val, "m2 should have been allowed to switch to m2!");
            Assert.AreEqual(0.0, m1.Val, "m1 shoudl have flipped to zero in order to allow m2 to change");

            r.Val = 8.0;
            Assert.AreEqual(2.0, m2.Val, "m2 should have stayed the same for the change in r");
            Assert.AreEqual(4.0, m1.Val, "m1 should have swtiched to compensate for the change in r");
        }

        [TestMethod]
        [ExpectedException(typeof(System.ArgumentException))]
        public void TestInitialBadConfig()
        {
            Value r = new Value();
            Value m1 = new Value();
            Value m2 = new Value();

            r.MaxValue = 10.0;
            m1.Val = 10.0;
            m2.Val = 10.0;

            Multiplication.Create(new Operand(r), new Operand[]{ new Operand(m1), new Operand(m2)});

        }
    }
}